package com.mapforge.gui.map;

//JRE
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;

import javax.swing.JComponent;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;

import com.mapforge.map.TileMap;

/**
 * Used to display an AbstractTileBackground. For best effect, this component
 * should be placed in a JScrollPane. This component is scrollable, and
 * automatically draws a square where the user is current pointing on the map.
 * 
 * @author William Morrison
 */
public class TileMapPanel extends JComponent implements Scrollable {
	/**
	 * Default serial version ID, here to remove warnings
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * The map being displayed
	 */
	private transient TileMap tileMap;

	/**
	 * Amount this label is shifted on the horizontal axis when dragged.
	 */
	protected int dragXInc;

	/**
	 * Amount this label is shifted on the vertical axis dragged.
	 */
	protected int dragYInc;

	private Dimension preferredSize;

	public TileMapPanel() {
		this(null);
	}

	public TileMapPanel(TileMap tileMap) {
		super();
		preferredSize = new Dimension();
		if (tileMap != null) {
			setTiledMap(tileMap);
		}
		setAutoscrolls(true);
	}

	public void setTiledMap(TileMap map) {
		this.tileMap = map;
		dragXInc = map.getTileWidth();
		dragYInc = map.getTileHeight();
		revalidate();
	}

	public Dimension getPreferredSize() {
		if (tileMap != null) {
			preferredSize.width = (int) (tileMap.getWidth());
			preferredSize.height = (int) (tileMap.getHeight());
		} else {
			preferredSize.width = 0;
			preferredSize.height = 0;
		}
		return preferredSize;
	}

	/**
	 * Sets the amount this label is shifted on the X-Axis when dragged.
	 * 
	 * @param inc
	 *            new horizontal shift amount
	 */
	public void setHorizontalDrag(int inc) {
		dragXInc = inc;
	}

	/**
	 * Sets the amount this label is shifted on the Y-Axis when dragged.
	 * 
	 * @param inc
	 *            new vertical shift amount
	 */
	public void setVerticalDrag(int inc) {
		dragYInc = inc;
	}

	/**
	 * Returns the current horizontal shift amount for when this label is
	 * dragged.
	 * 
	 * @return current horizontal shift amount
	 */
	public int getHorizontalDrag() {
		return dragXInc;
	}

	/**
	 * Returns the current vertical shift amount for when this label is dragged.
	 * 
	 * @return current vertical shift amount
	 */
	public int getVerticalDrag() {
		return dragYInc;
	}

	public int getScrollableBlockIncrement(Rectangle visibleRect,
			int orientation, int direction) {
		if (tileMap != null) {
			return orientation == SwingConstants.HORIZONTAL ? visibleRect.width
					- tileMap.getTileWidth() : visibleRect.height
					- tileMap.getTileHeight();
		} else {
			return 0;
		}
	}

	public Dimension getPreferredScrollableViewportSize() {
		return getPreferredSize();
	}

	public boolean getScrollableTracksViewportWidth() {
		return false;
	}

	public boolean getScrollableTracksViewportHeight() {
		return false;
	}

	public int getScrollableUnitIncrement(Rectangle visibleRect,
			int orientation, int direction) {
		// Get the current position.
		int currentPosition = orientation == SwingConstants.HORIZONTAL ? visibleRect.x
				: visibleRect.y;
		int inc = orientation == SwingConstants.HORIZONTAL ? dragXInc
				: dragYInc;
		// Return the number of pixels between currentPosition
		// and the nearest tick mark in the indicated direction.
		if (direction < 0) {
			int newPosition = currentPosition - (currentPosition / inc) * inc;
			return (newPosition == 0) ? inc : newPosition;
		} else {
			return ((currentPosition / inc) + 1) * inc - currentPosition;
		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (tileMap != null) {
			Graphics2D g2d = (Graphics2D) g;
			g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
					RenderingHints.VALUE_RENDER_SPEED);
			g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
					RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
			g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
					RenderingHints.VALUE_DITHER_DISABLE);
			g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
					RenderingHints.VALUE_COLOR_RENDER_SPEED);

			Rectangle rect = this.getVisibleRect();
			g2d.setColor(this.getBackground());
			g2d.fillRect(rect.x, rect.y, rect.width, rect.height);

			tileMap.render(g2d);
		}
	}

	/** */
	public TileMap getTiledMap() {
		return tileMap;
	}
}
